using System;
using System.Data;
using System.Data.Common;
using System.Collections.Generic;
using System.Text;
using System.Globalization;

using RaisingStudio.Data.Common;
using RaisingStudio.Data.Common.Factories;
using RaisingStudio.Data.Expressions;
using RaisingStudio.Data.Providers.Adapters;
using RaisingStudio.Data.Providers.Adapters.Generic;
using RaisingStudio.Common.Reflection;
using RaisingStudio.Data.Common.Managers;
using System.Collections;
using System.Text.RegularExpressions;
using System.Runtime.Serialization;
using System.IO;

namespace RaisingStudio.Data.Providers
{
    public partial class DataContext : RaisingStudio.Data.Common.DataContextBase, IDataContext
    {
        #region CreateInstance
        private static object processedDirectory_lock = new object();
        private static Dictionary<string, object> processedDirectory = new Dictionary<string, object>();

        public static DataContext CreateInstance()
        {
            return new DataContext();
        }

        private static void ProcessAppending(string baseDirectory)
        {
            lock (processedDirectory_lock)
            {
                if ((!processedDirectory.ContainsKey(baseDirectory)) && (AppDomain.CurrentDomain.BaseDirectory != baseDirectory))
                {
                    // commands.config
                    CommandManager.Instance.AppendCommands(baseDirectory);
                    // connections.config
                    ConnectionFactory.AppendConnectionSettings(baseDirectory);
                    // converters.config
                    ConverterManager.Default.AppendConverters(baseDirectory);
                    // definitions.config
                    DefinitionManager.Instance.AppendDefinitions(baseDirectory);
                    // providers.config
                    ProviderManager.Instance.AppendProviders(baseDirectory);

                    // mark as processed.
                    processedDirectory.Add(baseDirectory, new System.Diagnostics.StackFrame(1).GetMethod());
                }
            }
        }

        public static DataContext CreateInstance(string baseDirectory)
        {
            ProcessAppending(baseDirectory);
            // TODO:
            return new DataContext() { BaseDirectory = baseDirectory };
        }

        public static DataContext CreateInstance(string baseDirectory, string connectionName)
        {
            ProcessAppending(baseDirectory);
            // TODO:
            return new DataContext(connectionName) { BaseDirectory = baseDirectory };
        }

        public static DataContext CreateInstance(string baseDirectory, DatabaseType databaseType, string connectionString)
        {
            ProcessAppending(baseDirectory);
            // TODO:
            return new DataContext(databaseType, connectionString) { BaseDirectory = baseDirectory };
        }

        public static DataContext CreateInstance(string baseDirectory, string providerName, string connectionString)
        {
            ProcessAppending(baseDirectory);
            // TODO:
            return new DataContext(providerName, connectionString) { BaseDirectory = baseDirectory };
        }
        #endregion


        #region Properties
        private string _baseDirectory;
        public string BaseDirectory
        {
            get
            {
                return this._baseDirectory;
            }
            set
            {
                this._baseDirectory = value;
                if ((this._provider != null) && (this._provider.Connection != null) && (this._provider.Connection.ConnectionString != null))
                {
                    var expandedConnectionString = (new ConnectionOptions(this._provider.Connection.ConnectionString).GetExpandBaseDirectoriesConnectionString(this._baseDirectory));
                    if(expandedConnectionString != null)
                    {
                        this._provider.Connection.ConnectionString = expandedConnectionString;
                    }
                }
            }
        }

        #region ConnectionOptions
        public class ConnectionOptions
        {
            [Serializable]
            internal sealed class NameValuePair
            {
                private readonly string _name;
                private readonly string _value;
                [OptionalField(VersionAdded = 2)]
                private readonly int _length;
                private NameValuePair _next;
                internal int Length
                {
                    get
                    {
                        return this._length;
                    }
                }
                internal string Name
                {
                    get
                    {
                        return this._name;
                    }
                }
                internal NameValuePair Next
                {
                    get
                    {
                        return this._next;
                    }
                    set
                    {
                        if (this._next != null || value == null)
                        {
                            throw new ApplicationException("(this._next != null || value == null)");
                        }
                        this._next = value;
                    }
                }
                internal string Value
                {
                    get
                    {
                        return this._value;
                    }
                }
                internal NameValuePair(string name, string value, int length)
                {
                    this._name = name;
                    this._value = value;
                    this._length = length;
                }
            }

            private enum ParserState
            {
                NothingYet = 1,
                Key,
                KeyEqual,
                KeyEnd,
                UnquotedValue,
                DoubleQuoteValue,
                DoubleQuoteValueQuote,
                SingleQuoteValue,
                SingleQuoteValueQuote,
                BraceQuoteValue,
                BraceQuoteValueQuote,
                QuotedValueEnd,
                NullTermination
            }

            internal const string BaseDirectory = "|BaseDirectory|";

            private const string ConnectionStringValidKeyPattern = "^(?![;\\s])[^\\p{Cc}]+(?<!\\s)$";
            private const string ConnectionStringValidValuePattern = "^[^\0]*$";
            private const string ConnectionStringQuoteValuePattern = "^[^\"'=;\\s\\p{Cc}]*$";
            private const string ConnectionStringQuoteOdbcValuePattern = "^\\{([^\\}\0]|\\}\\})*\\}$";

            private static readonly Regex ConnectionStringValidKeyRegex = new Regex("^(?![;\\s])[^\\p{Cc}]+(?<!\\s)$", RegexOptions.Compiled);
            private static readonly Regex ConnectionStringValidValueRegex = new Regex("^[^\0]*$", RegexOptions.Compiled);
            private static readonly Regex ConnectionStringQuoteValueRegex = new Regex("^[^\"'=;\\s\\p{Cc}]*$", RegexOptions.Compiled);
            private static readonly Regex ConnectionStringQuoteOdbcValueRegex = new Regex("^\\{([^\\}\0]|\\}\\})*\\}$", RegexOptions.ExplicitCapture | RegexOptions.Compiled);


            private readonly Hashtable _parsetable;
            internal Hashtable Parsetable
            {
                get
                {
                    return this._parsetable;
                }
            }

            public string this[string keyword]
            {
                get
                {
                    return (string)this._parsetable[keyword];
                }
            }


            private readonly string _usersConnectionString;
            internal readonly NameValuePair KeyChain;

            public ConnectionOptions(string connectionString)
            {
                this._parsetable = new Hashtable();
                this._usersConnectionString = ((connectionString != null) ? connectionString : "");
                if (0 < this._usersConnectionString.Length)
                {
                    this.KeyChain = ParseInternal(this._parsetable, this._usersConnectionString);
                }
            }

            private static bool IsKeyNameValid(string keyname)
            {
                return keyname != null && (0 < keyname.Length && ';' != keyname[0] && !char.IsWhiteSpace(keyname[0])) && -1 == keyname.IndexOf('\0');
            }

            private static string GetKeyName(StringBuilder buffer)
            {
                int num = buffer.Length;
                while (0 < num && char.IsWhiteSpace(buffer[num - 1]))
                {
                    num--;
                }
                return buffer.ToString(0, num).ToLower(CultureInfo.InvariantCulture);
            }
            private static string GetKeyValue(StringBuilder buffer, bool trimWhitespace)
            {
                int num = buffer.Length;
                int i = 0;
                if (trimWhitespace)
                {
                    while (i < num)
                    {
                        if (!char.IsWhiteSpace(buffer[i]))
                        {
                            break;
                        }
                        i++;
                    }
                    while (0 < num && char.IsWhiteSpace(buffer[num - 1]))
                    {
                        num--;
                    }
                }
                return buffer.ToString(i, num - i);
            }

            internal static int GetKeyValuePair(string connectionString, int currentPosition, StringBuilder buffer, bool useOdbcRules, out string keyname, out string keyvalue)
            {
                int index = currentPosition;
                buffer.Length = 0;
                keyname = null;
                keyvalue = null;
                char c = '\0';
                ParserState parserState = ParserState.NothingYet;
                int length = connectionString.Length;
                while (currentPosition < length)
                {
                    c = connectionString[currentPosition];
                    switch (parserState)
                    {
                        case ParserState.NothingYet:
                            {
                                if (';' != c && !char.IsWhiteSpace(c))
                                {
                                    if (c == '\0')
                                    {
                                        parserState = ParserState.NullTermination;
                                    }
                                    else
                                    {
                                        if (char.IsControl(c))
                                        {
                                            throw new InvalidExpressionException(index.ToString());
                                        }
                                        index = currentPosition;
                                        if ('=' != c)
                                        {
                                            parserState = ParserState.Key;
                                            goto IL_24D;
                                        }
                                        parserState = ParserState.KeyEqual;
                                    }
                                }
                                break;
                            }
                        case ParserState.Key:
                            {
                                if ('=' == c)
                                {
                                    parserState = ParserState.KeyEqual;
                                }
                                else
                                {
                                    if (!char.IsWhiteSpace(c) && char.IsControl(c))
                                    {
                                        throw new InvalidExpressionException(index.ToString());
                                    }
                                    goto IL_24D;
                                }
                                break;
                            }
                        case ParserState.KeyEqual:
                            {
                                if (!useOdbcRules && '=' == c)
                                {
                                    parserState = ParserState.Key;
                                    goto IL_24D;
                                }
                                keyname = GetKeyName(buffer);
                                if (string.IsNullOrEmpty(keyname))
                                {
                                    throw new InvalidExpressionException(index.ToString());
                                }
                                buffer.Length = 0;
                                parserState = ParserState.KeyEnd;
                                goto IL_10C;
                            }
                        case ParserState.KeyEnd:
                            {
                                goto IL_10C;
                            }
                        case ParserState.UnquotedValue:
                            {
                                if (char.IsWhiteSpace(c))
                                {
                                    goto IL_24D;
                                }
                                if (char.IsControl(c))
                                {
                                    goto IL_262;
                                }
                                if (';' == c)
                                {
                                    goto IL_262;
                                }
                                goto IL_24D;
                            }
                        case ParserState.DoubleQuoteValue:
                            {
                                if ('"' == c)
                                {
                                    parserState = ParserState.DoubleQuoteValueQuote;
                                }
                                else
                                {
                                    if (c == '\0')
                                    {
                                        throw new InvalidExpressionException(index.ToString());
                                    }
                                    goto IL_24D;
                                }
                                break;
                            }
                        case ParserState.DoubleQuoteValueQuote:
                            {
                                if ('"' == c)
                                {
                                    parserState = ParserState.DoubleQuoteValue;
                                    goto IL_24D;
                                }
                                keyvalue = GetKeyValue(buffer, false);
                                parserState = ParserState.QuotedValueEnd;
                                goto IL_217;
                            }
                        case ParserState.SingleQuoteValue:
                            {
                                if ('\'' == c)
                                {
                                    parserState = ParserState.SingleQuoteValueQuote;
                                }
                                else
                                {
                                    if (c == '\0')
                                    {
                                        throw new InvalidExpressionException(index.ToString());
                                    }
                                    goto IL_24D;
                                }
                                break;
                            }
                        case ParserState.SingleQuoteValueQuote:
                            {
                                if ('\'' == c)
                                {
                                    parserState = ParserState.SingleQuoteValue;
                                    goto IL_24D;
                                }
                                keyvalue = GetKeyValue(buffer, false);
                                parserState = ParserState.QuotedValueEnd;
                                goto IL_217;
                            }
                        case ParserState.BraceQuoteValue:
                            {
                                if ('}' == c)
                                {
                                    parserState = ParserState.BraceQuoteValueQuote;
                                    goto IL_24D;
                                }
                                if (c == '\0')
                                {
                                    throw new InvalidExpressionException(index.ToString());
                                }
                                goto IL_24D;
                            }
                        case ParserState.BraceQuoteValueQuote:
                            {
                                if ('}' == c)
                                {
                                    parserState = ParserState.BraceQuoteValue;
                                    goto IL_24D;
                                }
                                keyvalue = GetKeyValue(buffer, false);
                                parserState = ParserState.QuotedValueEnd;
                                goto IL_217;
                            }
                        case ParserState.QuotedValueEnd:
                            {
                                goto IL_217;
                            }
                        case ParserState.NullTermination:
                            {
                                if (c != '\0' && !char.IsWhiteSpace(c))
                                {
                                    throw new InvalidExpressionException(currentPosition.ToString());
                                }
                                break;
                            }
                        default:
                            {
                                throw new InvalidExpressionException();
                            }
                    }
                IL_255:
                    currentPosition++;
                    continue;
                IL_10C:
                    if (char.IsWhiteSpace(c))
                    {
                        goto IL_255;
                    }
                    if (useOdbcRules)
                    {
                        if ('{' == c)
                        {
                            parserState = ParserState.BraceQuoteValue;
                            goto IL_24D;
                        }
                    }
                    else
                    {
                        if ('\'' == c)
                        {
                            parserState = ParserState.SingleQuoteValue;
                            goto IL_255;
                        }
                        if ('"' == c)
                        {
                            parserState = ParserState.DoubleQuoteValue;
                            goto IL_255;
                        }
                    }
                    if (';' == c || c == '\0')
                    {
                        break;
                    }
                    if (char.IsControl(c))
                    {
                        throw new InvalidExpressionException(index.ToString());
                    }
                    parserState = ParserState.UnquotedValue;
                    goto IL_24D;
                IL_217:
                    if (char.IsWhiteSpace(c))
                    {
                        goto IL_255;
                    }
                    if (';' == c)
                    {
                        break;
                    }
                    if (c == '\0')
                    {
                        parserState = ParserState.NullTermination;
                        goto IL_255;
                    }
                    throw new InvalidExpressionException(index.ToString());
                IL_24D:
                    buffer.Append(c);
                    goto IL_255;
                }
            IL_262:
                switch (parserState)
                {
                    case ParserState.NothingYet:
                    case ParserState.KeyEnd:
                    case ParserState.NullTermination:
                        {
                            break;
                        }
                    case ParserState.Key:
                    case ParserState.DoubleQuoteValue:
                    case ParserState.SingleQuoteValue:
                    case ParserState.BraceQuoteValue:
                        {
                            throw new InvalidExpressionException(index.ToString());
                        }
                    case ParserState.KeyEqual:
                        {
                            keyname = GetKeyName(buffer);
                            if (string.IsNullOrEmpty(keyname))
                            {
                                throw new InvalidExpressionException(index.ToString());
                            }
                            break;
                        }
                    case ParserState.UnquotedValue:
                        {
                            keyvalue = GetKeyValue(buffer, true);
                            char c2 = keyvalue[keyvalue.Length - 1];
                            if (!useOdbcRules && ('\'' == c2 || '"' == c2))
                            {
                                throw new InvalidExpressionException(index.ToString());
                            }
                            break;
                        }
                    case ParserState.DoubleQuoteValueQuote:
                    case ParserState.SingleQuoteValueQuote:
                    case ParserState.BraceQuoteValueQuote:
                    case ParserState.QuotedValueEnd:
                        {
                            keyvalue = GetKeyValue(buffer, false);
                            break;
                        }
                    default:
                        {
                            throw new InvalidExpressionException();
                        }
                }
                if (';' == c && currentPosition < connectionString.Length)
                {
                    currentPosition++;
                }
                return currentPosition;
            }
            private static NameValuePair ParseInternal(Hashtable parsetable, string connectionString)
            {
                StringBuilder buffer = new StringBuilder();
                NameValuePair nameValuePair = null;
                NameValuePair result = null;
                int i = 0;
                int length = connectionString.Length;
                while (i < length)
                {
                    int num = i;
                    string text;
                    string value;
                    i = GetKeyValuePair(connectionString, num, buffer, false, out text, out value);
                    if (string.IsNullOrEmpty(text))
                    {
                        break;
                    }
                    string text2 = text;
                    if (!IsKeyNameValid(text2))
                    {
                        throw new NotSupportedException(text);
                    }
                    if (!parsetable.Contains(text2))
                    {
                        parsetable[text2] = value;
                    }
                    if (nameValuePair != null)
                    {
                        nameValuePair = (nameValuePair.Next = new NameValuePair(text2, value, i - num));
                    }
                    else
                    {
                        nameValuePair = (result = new NameValuePair(text2, value, i - num));
                    }
                }
                return result;
            }

            internal static void CheckArgumentNull(object value, string parameterName)
            {
                if (value == null)
                {
                    throw new ArgumentNullException(parameterName);
                }
            }
            internal static void CheckArgumentLength(string value, string parameterName)
            {
                CheckArgumentNull(value, parameterName);
                if (value.Length == 0)
                {
                    throw new ArgumentException(parameterName);
                }
            }

            private static bool IsValueValidInternal(string keyvalue)
            {
                return keyvalue == null || -1 == keyvalue.IndexOf('\0');
            }

            internal static void AppendKeyValuePairBuilder(StringBuilder builder, string keyName, string keyValue, bool useOdbcRules)
            {
                CheckArgumentNull(builder, "builder");
                CheckArgumentLength(keyName, "keyName");
                if (keyName == null || !ConnectionStringValidKeyRegex.IsMatch(keyName))
                {
                    throw new InvalidExpressionException(keyName);
                }
                if (keyValue != null && !IsValueValidInternal(keyValue))
                {
                    throw new InvalidExpressionException(keyName);
                }
                if (0 < builder.Length && ';' != builder[builder.Length - 1])
                {
                    builder.Append(";");
                }
                if (useOdbcRules)
                {
                    builder.Append(keyName);
                }
                else
                {
                    builder.Append(keyName.Replace("=", "=="));
                }
                builder.Append("=");
                if (keyValue != null)
                {
                    if (useOdbcRules)
                    {
                        if (0 < keyValue.Length && ('{' == keyValue[0] || 0 <= keyValue.IndexOf(';') || string.Compare("Driver", keyName, StringComparison.OrdinalIgnoreCase) == 0) && !ConnectionOptions.ConnectionStringQuoteOdbcValueRegex.IsMatch(keyValue))
                        {
                            builder.Append('{').Append(keyValue.Replace("}", "}}")).Append('}');
                            return;
                        }
                        builder.Append(keyValue);
                        return;
                    }
                    else
                    {
                        if (ConnectionStringQuoteValueRegex.IsMatch(keyValue))
                        {
                            builder.Append(keyValue);
                            return;
                        }
                        if (-1 != keyValue.IndexOf('"') && -1 == keyValue.IndexOf('\''))
                        {
                            builder.Append('\'');
                            builder.Append(keyValue);
                            builder.Append('\'');
                            return;
                        }
                        builder.Append('"');
                        builder.Append(keyValue.Replace("\"", "\"\""));
                        builder.Append('"');
                    }
                }
            }

            internal static string ExpandBaseDirectory(string keyword, string value, ref string datadir)
            {
                string text = null;// value;
                if (value != null && value.StartsWith(BaseDirectory, StringComparison.OrdinalIgnoreCase))
                {
                    string text2 = datadir;
                    if (text2 == null)
                    {
                        object data = AppDomain.CurrentDomain.GetData("BaseDirectory");
                        text2 = (data as string);
                        if (data != null && text2 == null)
                        {
                            throw new System.IO.DirectoryNotFoundException();
                        }
                        if (string.IsNullOrEmpty(text2))
                        {
                            text2 = AppDomain.CurrentDomain.BaseDirectory;
                        }
                        if (text2 == null)
                        {
                            text2 = "";
                        }
                        datadir = text2;
                    }
                    int length = BaseDirectory.Length;
                    bool flag = 0 < text2.Length && text2[text2.Length - 1] == '\\';
                    bool flag2 = length < value.Length && value[length] == '\\';
                    if (!flag && !flag2)
                    {
                        text = text2 + '\\' + value.Substring(length);
                    }
                    else
                    {
                        if (flag && flag2)
                        {
                            text = text2 + value.Substring(length + 1);
                        }
                        else
                        {
                            text = text2 + value.Substring(length);
                        }
                    }
                    if (!Path.GetFullPath(text).StartsWith(text2, StringComparison.Ordinal))
                    {
                        throw new InvalidExpressionException(keyword);
                    }
                }
                return text;
            }
            internal string ExpandBaseDirectories(ref string filename, ref int position, ref string datadir)
            {
                string text = null;
                StringBuilder stringBuilder = new StringBuilder(this._usersConnectionString.Length);               
                int num = 0;
                bool flag = false;
                for (NameValuePair nameValuePair = this.KeyChain; nameValuePair != null; nameValuePair = nameValuePair.Next)
                {
                    text = nameValuePair.Value;

                    string name2;
                    switch (name2 = nameValuePair.Name)
                    {
                        case "provider":
                        case "data provider":
                        case "remote provider":
                        case "extended properties":
                        case "user id":
                        case "password":
                        case "uid":
                        case "pwd":
                            {
                                goto IL_151;
                            }
                    }
                    text = ExpandBaseDirectory(nameValuePair.Name, text, ref datadir);
                IL_151:
                    if (text == null)
                    {
                        text = nameValuePair.Value;
                    }
                    if ("file name" != nameValuePair.Name)
                    {
                        if (text != nameValuePair.Value)
                        {
                            flag = true;
                            AppendKeyValuePairBuilder(stringBuilder, nameValuePair.Name, text, false);
                            stringBuilder.Append(';');
                        }
                        else
                        {
                            stringBuilder.Append(this._usersConnectionString, num, nameValuePair.Length);
                        }
                    }
                    else
                    {
                        flag = true;
                        filename = text;
                        position = stringBuilder.Length;
                    }
                    num += nameValuePair.Length;
                }
                if (flag)
                {
                    text = stringBuilder.ToString();
                }
                else
                {
                    text = null;
                }
                return text;
            }

            public string GetExpandBaseDirectoriesConnectionString(string baseDirectory)
            {
                string filename = null;
                int position = -1;
                if (!Path.IsPathRooted(baseDirectory))
                {
                    baseDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, baseDirectory);
                }
                return ExpandBaseDirectories(ref filename, ref position, ref baseDirectory);
            }
        }
        #endregion

        private DataProvider _provider;
        /// <summary>
        /// Data Provider.
        /// </summary>
        public IDataProvider Provider
        {
            get { return _provider; }
        }

        public bool UseDynamicProxy
        {
            get
            {
                return this._provider.UseDynamicProxy;
            }
            set
            {
                this._provider.UseDynamicProxy = value;
            }
        }

        public bool CacheDefalutCommand
        {
            get
            {
                return this._provider.CacheDefalutCommand;
            }
            set
            {
                this._provider.CacheDefalutCommand = value;
            }
        }

        private CommonDatabase _database;
        /// <summary>
        /// Database.
        /// </summary>
        public ICommonDatabase Database
        {
            get { return _database; }
        }
        #endregion

        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        public DataContext()
        {
            this._provider = new DataProvider(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
            this._database = new CommonDatabase(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="connection">database connection.</param>
        public DataContext(System.Data.IDbConnection connection)
            : base(connection)
        {
            this._provider = new DataProvider(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
            this._database = new CommonDatabase(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="transactionManager">database transaction manager.</param>
        public DataContext(TransactionManager transactionManager)
            : base(transactionManager)
        {
            this._provider = new DataProvider(transactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
            this._database = new CommonDatabase(transactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="connectionName">the name of connection.</param>
        public DataContext(string connectionName)
            : base(connectionName)
        {
            this._provider = new DataProvider(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
            this._database = new CommonDatabase(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="databaseType">database type.</param>
        /// <param name="connectionString">connection string.</param>
        public DataContext(DatabaseType databaseType, string connectionString)
            : base(databaseType, connectionString)
        {
            this._provider = new DataProvider(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
            this._database = new CommonDatabase(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="providerName">provider name.</param>
        /// <param name="connectionString">connection string.</param>
        public DataContext(string providerName, string connectionString)
            : base(providerName, connectionString)
        {
            this._provider = new DataProvider(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
            this._database = new CommonDatabase(base.TransactionManager, base.LogManager as LogManager, base.DatabaseType, base.ProviderName);
        }
        #endregion

        #region Private methods
        /// <summary>
        /// Convert property value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <param name="value">Value.</param>
        /// <returns>The value that converted.</returns>
        private object ConvertPropertyValue<T>(ColumnExpression column, object value)
        {
            // TODO: convert the input value into the property type.
            // 2009-03-06 sometimes, it seems that no need to do that. for example, if the column is bool type or enum type, 
            // the convert doesn't make sense.
            return value;
        }
        /// <summary>
        /// Get the column names in value.
        /// </summary>
        /// <param name="columnNames">Column names.</param>
        /// <param name="sourceNames">Souce names.</param>
        /// <param name="valueNames">Value names.</param>
        /// <returns>Column names contains value names.</returns>
        private List<string> GetColumnNamesInValue(List<string> columnNames, Dictionary<string, string> sourceNames, List<string> valueNames)
        {
            foreach (KeyValuePair<string, string> keyValuePair in sourceNames)
            {
                string columnName = keyValuePair.Key;
                string sourceName = keyValuePair.Value;
                if (!valueNames.Contains(sourceName))
                {
                    columnNames.Remove(columnName);
                }
            }
            return columnNames;
        }
        /// <summary>
        /// Get column names contains in datareader.
        /// </summary>
        /// <param name="dataReader">DataReader.</param>
        /// <returns>Column names.</returns>
        private List<string> GetDataReaderValueNames(System.Data.IDataReader dataReader)
        {
            List<string> columnNames = new List<string>();
            for (int i = 0; i < dataReader.FieldCount; i++)
            {
                columnNames.Add(dataReader.GetName(i));
            }
            return columnNames;
        }
        /// <summary>
        /// Create Data adapter.
        /// </summary>
        /// <param name="command">Command.</param>
        /// <returns>Data adapter.</returns>
        private DbDataAdapter CreateDbDataAdapter(CommonCommand command)
        {
            DataAdapterFactory dataAdapterFactory = new DataAdapterFactory(this.Connection, this.DatabaseType, this.ProviderName);
            DbDataAdapter adapter = dataAdapterFactory.CreateDataAdapter(command) as DbDataAdapter;
            if ((adapter != null) && ((adapter as IDbDataAdapter).SelectCommand != null))
            {
                System.Data.IDbTransaction transaction = this.TransactionManager.DefaultTransaction;
                if (transaction != null)
                {
                    ((adapter as IDbDataAdapter).SelectCommand as IDbCommand).Transaction = transaction as DbTransaction;
                }
            }
            return adapter;
        }

        /// <summary>
        /// Load DataSet.
        /// </summary>
        /// <param name="command">Command.</param>
        /// <param name="dataSet">DataSet.</param>
        /// <param name="tableName">Table name.</param>
        private void LoadDataSet(CommonCommand command, System.Data.DataSet dataSet, string tableName)
        {
            DbDataAdapter adapter = CreateDbDataAdapter(command);
            if (adapter != null)
            {
                try
                {
                    adapter.Fill(dataSet, tableName);
                }
                catch (Exception e)
                {
                    // TODO: exception.
                    throw;
                }
            }
        }
        /// <summary>
        /// Load DataSet.
        /// </summary>
        /// <param name="command">Command.</param>
        /// <param name="dataSet">DataSet.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <param name="tableName">Table name.</param>
        private void LoadDataSet(CommonCommand command, System.Data.DataSet dataSet, int startRecord, int maxRecords, string tableName)
        {
            DbDataAdapter adapter = CreateDbDataAdapter(command);
            if (adapter != null)
            {
                try
                {
                    adapter.Fill(dataSet, startRecord, maxRecords, tableName);
                }
                catch (Exception e)
                {
                    // TODO: exception.
                    throw;
                }
            }
        }
        #endregion

        #region Basic functions
        /// <summary>
        /// Get data count.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <returns>Data count.</returns>
        public int GetCount<T>()
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            return dataTableAdapter.GetDataCount();
        }
        /// <summary>
        /// Get data count.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condiion.</param>
        /// <returns>Data count.</returns>
        public int GetCount<T>(ConditionExpression condition)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            return dataTableAdapter.GetDataCount(condition);
        }

        /// <summary>
        /// Get data count.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <returns>Data count.</returns>
        public long GetLongCount<T>()
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            return dataTableAdapter.GetDataLongCount();
        }
        /// <summary>
        /// Get data count.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condiion.</param>
        /// <returns>Data count.</returns>
        public long GetLongCount<T>(ConditionExpression condition)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            return dataTableAdapter.GetDataLongCount(condition);
        }

        /// <summary>
        /// Get Sum value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <returns>Sum value.</returns>
        public object GetSum<T>(ColumnExpression column)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            object value = dataTableAdapter.GetSumData(column);
            return ConvertPropertyValue<T>(column, value);
        }
        /// <summary>
        /// Get Sum value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <param name="condition">Condiion.</param>
        /// <returns>Sum value.</returns>
        public object GetSum<T>(ColumnExpression column, ConditionExpression condition)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            object value = dataTableAdapter.GetSumData(column, condition);
            return ConvertPropertyValue<T>(column, value);
        }

        /// <summary>
        /// Get Avg value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <returns>Avg value.</returns>
        public object GetAvg<T>(ColumnExpression column)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            object value = dataTableAdapter.GetAvgData(column);
            return ConvertPropertyValue<T>(column, value);
        }
        /// <summary>
        /// Get Avg value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <param name="condition">Condiion.</param>
        /// <returns>Avg value.</returns>
        public object GetAvg<T>(ColumnExpression column, ConditionExpression condition)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            object value = dataTableAdapter.GetAvgData(column, condition);
            return ConvertPropertyValue<T>(column, value);
        }
        /// <summary>
        /// Get Max value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <returns>Max value.</returns>
        public object GetMax<T>(ColumnExpression column)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            object value = dataTableAdapter.GetMaxData(column);
            return ConvertPropertyValue<T>(column, value);
        }
        /// <summary>
        /// Get Max value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <param name="condition">Condiion.</param>
        /// <returns>Max value.</returns>
        public object GetMax<T>(ColumnExpression column, ConditionExpression condition)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            object value = dataTableAdapter.GetMaxData(column, condition);
            return ConvertPropertyValue<T>(column, value);
        }
        /// <summary>
        /// Get Min value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <returns>Min value.</returns>
        public object GetMin<T>(ColumnExpression column)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            object value = dataTableAdapter.GetMinData(column);
            return ConvertPropertyValue<T>(column, value);
        }
        /// <summary>
        /// Get Min value.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="column">Column.</param>
        /// <param name="condition">Condiion.</param>
        /// <returns>Min value.</returns>
        public object GetMin<T>(ColumnExpression column, ConditionExpression condition)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            object value = dataTableAdapter.GetMinData(column, condition);
            return ConvertPropertyValue<T>(column, value);
        }
        #endregion

        #region ExecuteQuery

        private IEnumerable<T> GetEnumerator<T>(IDataReader dataReader)
        {
            if (dataReader.FieldCount > 0)
            {
                try
                {
                    while (dataReader.Read())
                    {
                        if (dataReader.IsDBNull(0))
                        {
                            yield return default(T);
                        }
                        else
                        {
                            object value = dataReader.GetValue(0);
                            // TODO: convert.
#if (PocketPC || Smartphone || WindowsCE)
                            value = Convert.ChangeType(value, typeof(T), null);
#else
                            value = Convert.ChangeType(value, typeof(T));
#endif
                            yield return (T)value;
                        }
                    }
                }
                finally
                {
                    if (dataReader != null)
                    {
                        dataReader.Close();
                    }
                }
            }
        }
        /// <summary>
        /// Execute query command.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>Enumerator of given Type.</returns>
        public IEnumerable<T> ExecuteQuery<T>(CommonCommand command)
        {
            if (TypeManager.IsWellKnownDataType(typeof(T)))
            {
                System.Data.IDataReader dataReader = ExecuteReader(command);
                if (dataReader != null)
                {
                    return GetEnumerator<T>(dataReader);
                }
                else
                {
                    return null;
                }
            }
            else
            {
                DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
                System.Data.Common.DataTableMapping dataTableMapping = dataObjectAdapter.DefaultDataTableMapping;

                if (UseDynamicProxy)
                {
                    List<string> columnNames;
                    IObjectAccessor objectAccessor;
                    Dictionary<string, string> sourceNames;
                    Dictionary<string, System.Data.DbType> dbTypes;
                    Dictionary<string, DataConverter> propertyConverters;
                    dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out objectAccessor, out propertyConverters, out sourceNames, out dbTypes);
                    CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                    System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                    List<string> valueNames = GetDataReaderValueNames(dataReader);
                    List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                    return dataObjectAdapter.GetEnumerator(dataReader, columnNames, objectAccessor, propertyConverters, sourceNames, dbTypes);
                }
                else
                {
                    if ((typeof(IDataObjectProxy)).IsAssignableFrom(dataObjectAdapter.DataObjectType))
                    {
                        // proxy.
                        IDataObjectProxy proxy = System.Activator.CreateInstance(dataObjectAdapter.DataObjectType) as IDataObjectProxy;
                        List<string> columnNames;
                        Dictionary<string, string> sourceNames;
                        Dictionary<string, System.Data.DbType> dbTypes;
                        Dictionary<string, DataConverter> propertyConverters;
                        dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, proxy, out propertyConverters, out sourceNames, out dbTypes);
                        CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                        System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                        List<string> valueNames = GetDataReaderValueNames(dataReader);
                        List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                        return dataObjectAdapter.GetEnumerator(dataReader, columnNames, proxy, propertyConverters, sourceNames, dbTypes);
                    }
                    else
                    {
                        List<string> columnNames;
                        Dictionary<string, System.Reflection.PropertyInfo> propertyInfos;
                        Dictionary<string, string> sourceNames;
                        Dictionary<string, System.Data.DbType> dbTypes;
                        Dictionary<string, DataConverter> propertyConverters;
                        dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out propertyInfos, out propertyConverters, out sourceNames, out dbTypes);
                        CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                        System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                        List<string> valueNames = GetDataReaderValueNames(dataReader);
                        List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                        return dataObjectAdapter.GetEnumerator(dataReader, columnNames, propertyInfos, propertyConverters, sourceNames, dbTypes);
                    }
                }
            }
        }

        private IEnumerable<T> GetEnumerator<T>(IDataReader dataReader, int startRecord, int maxRecords)
        {
            if (dataReader.FieldCount > 0)
            {
                int index = 0;
                int count = 0;
                try
                {
                    while ((dataReader.Read()) && (count < maxRecords))
                    {
                        if (index >= startRecord)
                        {
                            if (dataReader.IsDBNull(0))
                            {
                                yield return default(T);
                            }
                            else
                            {
                                object value = dataReader.GetValue(0);
                                // TODO: convert.
#if (PocketPC || Smartphone || WindowsCE)
                            value = Convert.ChangeType(value, typeof(T), null);
#else
                                value = Convert.ChangeType(value, typeof(T));
#endif
                                yield return (T)value;
                            }
                            count++;
                        }
                        index++;
                    }
                }
                finally
                {
                    if (dataReader != null)
                    {
                        dataReader.Close();
                    }
                }
            }
        }
        /// <summary>
        /// Execute query command.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>Enumerator of given Type.</returns>
        public IEnumerable<T> ExecuteQuery<T>(CommonCommand command, int startRecord, int maxRecords)
        {
            if (TypeManager.IsWellKnownDataType(typeof(T)))
            {
                System.Data.IDataReader dataReader = ExecuteReader(command);
                if (dataReader != null)
                {
                    return GetEnumerator<T>(dataReader, startRecord, maxRecords);
                }
                else
                {
                    return null;
                }
            }
            else
            {
                DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
                System.Data.Common.DataTableMapping dataTableMapping = dataObjectAdapter.DefaultDataTableMapping;

                if (UseDynamicProxy)
                {
                    List<string> columnNames;
                    IObjectAccessor objectAccessor;
                    Dictionary<string, string> sourceNames;
                    Dictionary<string, System.Data.DbType> dbTypes;
                    Dictionary<string, DataConverter> propertyConverters;
                    dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out objectAccessor, out propertyConverters, out sourceNames, out dbTypes);
                    CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                    System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                    List<string> valueNames = GetDataReaderValueNames(dataReader);
                    List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                    return dataObjectAdapter.GetEnumerator(dataReader, columnNames, objectAccessor, propertyConverters, sourceNames, dbTypes, startRecord, maxRecords);
                }
                else
                {
                    if ((typeof(IDataObjectProxy)).IsAssignableFrom(dataObjectAdapter.DataObjectType))
                    {
                        // proxy.
                        IDataObjectProxy proxy = System.Activator.CreateInstance(dataObjectAdapter.DataObjectType) as IDataObjectProxy;
                        List<string> columnNames;
                        Dictionary<string, string> sourceNames;
                        Dictionary<string, System.Data.DbType> dbTypes;
                        Dictionary<string, DataConverter> propertyConverters;
                        dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, proxy, out propertyConverters, out sourceNames, out dbTypes);
                        CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                        System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                        List<string> valueNames = GetDataReaderValueNames(dataReader);
                        List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                        return dataObjectAdapter.GetEnumerator(dataReader, columnNames, proxy, propertyConverters, sourceNames, dbTypes, startRecord, maxRecords);
                    }
                    else
                    {
                        List<string> columnNames;
                        Dictionary<string, System.Reflection.PropertyInfo> propertyInfos;
                        Dictionary<string, string> sourceNames;
                        Dictionary<string, System.Data.DbType> dbTypes;
                        Dictionary<string, DataConverter> propertyConverters;
                        dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out propertyInfos, out propertyConverters, out sourceNames, out dbTypes);
                        CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                        System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                        List<string> valueNames = GetDataReaderValueNames(dataReader);
                        List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                        return dataObjectAdapter.GetEnumerator(dataReader, columnNames, propertyInfos, propertyConverters, sourceNames, dbTypes, startRecord, maxRecords);
                    }
                }
            }
        }

        /// <summary>
        /// Execute query command for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>IList of given Type.</returns>
        public List<T> ExecuteForList<T>(CommonCommand command)
        {
            if (TypeManager.IsWellKnownDataType(typeof(T)))
            {
                System.Data.IDataReader dataReader = ExecuteReader(command);
                if (dataReader != null)
                {
                    List<T> dataObjectList = new List<T>();
                    if (dataReader.FieldCount > 0)
                    {
                        try
                        {
                            while (dataReader.Read())
                            {
                                if (dataReader.IsDBNull(0))
                                {
                                    dataObjectList.Add(default(T));
                                }
                                else
                                {
                                    object value = dataReader.GetValue(0);
                                    // TODO: convert.
#if (PocketPC || Smartphone || WindowsCE)
                            value = Convert.ChangeType(value, typeof(T), null);
#else
                                    value = Convert.ChangeType(value, typeof(T));
#endif
                                    dataObjectList.Add((T)value);
                                }
                            }
                        }
                        finally
                        {
                            if (dataReader != null)
                            {
                                dataReader.Close();
                            }
                        }
                    }
                    return dataObjectList;
                }
                else
                {
                    return null;
                }
            }
            else
            {
#if !(PocketPC || Smartphone || WindowsCE)
                if (this.DatabaseType == DatabaseType.SHAREPOINT)
                {
                    List<T> dataObjectList = new List<T>();
                    DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
                    System.Data.Common.DataTableMapping dataTableMapping = dataObjectAdapter.DefaultDataTableMapping;
                    if (UseDynamicProxy)
                    {
                        List<string> columnNames;
                        IObjectAccessor objectAccessor;
                        Dictionary<string, string> sourceNames;
                        Dictionary<string, System.Data.DbType> dbTypes;
                        Dictionary<string, DataConverter> propertyConverters;
                        dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out objectAccessor, out propertyConverters, out sourceNames, out dbTypes);
                        CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);                        
                        System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                        (dataReader as System.Data.SharePoint.SharePointDataReader).ListUrl = dataTableMapping.SourceTable;
                        List<string> valueNames = GetDataReaderValueNames(dataReader);
                        List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                        dataObjectAdapter.FillDataObjectList(dataReader, dataObjectList, columnNames, objectAccessor, propertyConverters, sourceNames, dbTypes);
                    }
                    else
                    {
                        if ((typeof(IDataObjectProxy)).IsAssignableFrom(dataObjectAdapter.DataObjectType))
                        {
                            // proxy.
                            IDataObjectProxy proxy = System.Activator.CreateInstance(dataObjectAdapter.DataObjectType) as IDataObjectProxy;
                            List<string> columnNames;
                            Dictionary<string, string> sourceNames;
                            Dictionary<string, System.Data.DbType> dbTypes;
                            Dictionary<string, DataConverter> propertyConverters;
                            dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, proxy, out propertyConverters, out sourceNames, out dbTypes);
                            CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                            System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                            (dataReader as System.Data.SharePoint.SharePointDataReader).ListUrl = dataTableMapping.SourceTable;
                            List<string> valueNames = GetDataReaderValueNames(dataReader);
                            List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                            dataObjectAdapter.FillDataObjectList(dataReader, dataObjectList, columnNames, proxy, propertyConverters, sourceNames, dbTypes);
                        }
                        else
                        {
                            List<string> columnNames;
                            Dictionary<string, System.Reflection.PropertyInfo> propertyInfos;
                            Dictionary<string, string> sourceNames;
                            Dictionary<string, System.Data.DbType> dbTypes;
                            Dictionary<string, DataConverter> propertyConverters;
                            dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out propertyInfos, out propertyConverters, out sourceNames, out dbTypes);
                            CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                            System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                            (dataReader as System.Data.SharePoint.SharePointDataReader).ListUrl = dataTableMapping.SourceTable;
                            List<string> valueNames = GetDataReaderValueNames(dataReader);
                            List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                            dataObjectAdapter.FillDataObjectList(dataReader, dataObjectList, columnNames, propertyInfos, propertyConverters, sourceNames, dbTypes);
                        }
                    }
                    return dataObjectList;
                }
                else
#endif
                {
                    List<T> dataObjectList = new List<T>();
                    DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
                    System.Data.Common.DataTableMapping dataTableMapping = dataObjectAdapter.DefaultDataTableMapping;
                    if (UseDynamicProxy)
                    {
                        List<string> columnNames;
                        IObjectAccessor objectAccessor;
                        Dictionary<string, string> sourceNames;
                        Dictionary<string, System.Data.DbType> dbTypes;
                        Dictionary<string, DataConverter> propertyConverters;
                        dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out objectAccessor, out propertyConverters, out sourceNames, out dbTypes);
                        CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                        System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                        List<string> valueNames = GetDataReaderValueNames(dataReader);
                        List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                        dataObjectAdapter.FillDataObjectList(dataReader, dataObjectList, columnNames, objectAccessor, propertyConverters, sourceNames, dbTypes);
                    }
                    else
                    {
                        if ((typeof(IDataObjectProxy)).IsAssignableFrom(dataObjectAdapter.DataObjectType))
                        {
                            // proxy.
                            IDataObjectProxy proxy = System.Activator.CreateInstance(dataObjectAdapter.DataObjectType) as IDataObjectProxy;
                            List<string> columnNames;
                            Dictionary<string, string> sourceNames;
                            Dictionary<string, System.Data.DbType> dbTypes;
                            Dictionary<string, DataConverter> propertyConverters;
                            dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, proxy, out propertyConverters, out sourceNames, out dbTypes);
                            CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                            System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                            List<string> valueNames = GetDataReaderValueNames(dataReader);
                            List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                            dataObjectAdapter.FillDataObjectList(dataReader, dataObjectList, columnNames, proxy, propertyConverters, sourceNames, dbTypes);
                        }
                        else
                        {
                            List<string> columnNames;
                            Dictionary<string, System.Reflection.PropertyInfo> propertyInfos;
                            Dictionary<string, string> sourceNames;
                            Dictionary<string, System.Data.DbType> dbTypes;
                            Dictionary<string, DataConverter> propertyConverters;
                            dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out propertyInfos, out propertyConverters, out sourceNames, out dbTypes);
                            CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                            System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                            List<string> valueNames = GetDataReaderValueNames(dataReader);
                            List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                            dataObjectAdapter.FillDataObjectList(dataReader, dataObjectList, columnNames, propertyInfos, propertyConverters, sourceNames, dbTypes);
                        }
                    }
                    return dataObjectList;
                }
            }
        }

        /// <summary>
        /// Execute query command for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>IList of given Type.</returns>
        public List<T> ExecuteForList<T>(CommonCommand command, int startRecord, int maxRecords)
        {
            if (TypeManager.IsWellKnownDataType(typeof(T)))
            {
                System.Data.IDataReader dataReader = ExecuteReader(command);
                if (dataReader != null)
                {
                    List<T> dataObjectList = new List<T>();
                    if (dataReader.FieldCount > 0)
                    {
                        int index = 0;
                        int count = 0;
                        try
                        {
                            while ((dataReader.Read()) && (count < maxRecords))
                            {
                                if (index >= startRecord)
                                {
                                    if (dataReader.IsDBNull(0))
                                    {
                                        dataObjectList.Add(default(T));
                                    }
                                    else
                                    {
                                        object value = dataReader.GetValue(0);
                                        // TODO: convert.
#if (PocketPC || Smartphone || WindowsCE)
                            value = Convert.ChangeType(value, typeof(T), null);
#else
                                        value = Convert.ChangeType(value, typeof(T));
#endif
                                        dataObjectList.Add((T)value);
                                    }
                                    count++;
                                }
                                index++;
                            }
                        }
                        finally
                        {
                            if (dataReader != null)
                            {
                                dataReader.Close();
                            }
                        }
                    }
                    return dataObjectList;
                }
                else
                {
                    return null;
                }
            }
            else
            {
                List<T> dataObjectList = new List<T>();
                DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
                System.Data.Common.DataTableMapping dataTableMapping = dataObjectAdapter.DefaultDataTableMapping;
                if (UseDynamicProxy)
                {
                    List<string> columnNames;
                    IObjectAccessor objectAccessor;
                    Dictionary<string, string> sourceNames;
                    Dictionary<string, System.Data.DbType> dbTypes;
                    Dictionary<string, DataConverter> propertyConverters;
                    dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out objectAccessor, out propertyConverters, out sourceNames, out dbTypes);
                    CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                    System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                    List<string> valueNames = GetDataReaderValueNames(dataReader);
                    List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                    dataObjectAdapter.FillDataObjectList(dataReader, dataObjectList, columnNames, objectAccessor, propertyConverters, sourceNames, dbTypes, startRecord, maxRecords);
                }
                else
                {
                    if ((typeof(IDataObjectProxy)).IsAssignableFrom(dataObjectAdapter.DataObjectType))
                    {
                        // proxy.
                        IDataObjectProxy proxy = System.Activator.CreateInstance(dataObjectAdapter.DataObjectType) as IDataObjectProxy;
                        List<string> columnNames;
                        Dictionary<string, string> sourceNames;
                        Dictionary<string, System.Data.DbType> dbTypes;
                        Dictionary<string, DataConverter> propertyConverters;
                        dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, proxy, out propertyConverters, out sourceNames, out dbTypes);
                        CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                        System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                        List<string> valueNames = GetDataReaderValueNames(dataReader);
                        List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                        dataObjectAdapter.FillDataObjectList(dataReader, dataObjectList, columnNames, proxy, propertyConverters, sourceNames, dbTypes, startRecord, maxRecords);
                    }
                    else
                    {
                        List<string> columnNames;
                        Dictionary<string, System.Reflection.PropertyInfo> propertyInfos;
                        Dictionary<string, string> sourceNames;
                        Dictionary<string, System.Data.DbType> dbTypes;
                        Dictionary<string, DataConverter> propertyConverters;
                        dataObjectAdapter.BuildMappingInfo(dataTableMapping, out columnNames, out propertyInfos, out propertyConverters, out sourceNames, out dbTypes);
                        CommonCommand mappingCommand = dataObjectAdapter.CommandBuilder.CommonCommandBuilder.GetMappingCommand(command);
                        System.Data.IDataReader dataReader = this._database.ExecuteReaderCommand(mappingCommand);
                        List<string> valueNames = GetDataReaderValueNames(dataReader);
                        List<string> columnNamesInValue = GetColumnNamesInValue(columnNames, sourceNames, valueNames);
                        dataObjectAdapter.FillDataObjectList(dataReader, dataObjectList, columnNames, propertyInfos, propertyConverters, sourceNames, dbTypes, startRecord, maxRecords);
                    }
                }
                return dataObjectList;
            }
        }

        /// <summary>
        /// Execute query command for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>DataTable.</returns>
        public System.Data.DataTable ExecuteForDataTable<T>(CommonCommand command)
        {
            return this._provider.ExecuteDataTable(typeof(T), command);
        }
        /// <summary>
        /// Execute query command for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>DataTable.</returns>
        public System.Data.DataTable ExecuteForDataTable<T>(CommonCommand command, int startRecord, int maxRecords)
        {
            return this._provider.ExecuteDataTable(typeof(T), command, startRecord, maxRecords);
        }
        /// <summary>
        /// Execute query command for DataTable.
        /// </summary>
        /// <param name="command">Command.</param>
        /// <returns>DataTable.</returns>
        public System.Data.DataTable ExecuteForDataTable(CommonCommand command)
        {
            System.Data.DataSet dataSet = new System.Data.DataSet();
            dataSet.Locale = CultureInfo.InvariantCulture;
            LoadDataSet(command, dataSet, "Table");
            if (dataSet.Tables.Count > 0)
            {
                return dataSet.Tables[0];
            }
            return null;
        }
        /// <summary>
        /// Execute query command for DataTable.
        /// </summary>
        /// <param name="command">Command.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <returns>DataTable.</returns>
        public System.Data.DataTable ExecuteForDataTable(CommonCommand command, int startRecord, int maxRecords)
        {
            System.Data.DataSet dataSet = new System.Data.DataSet();
            dataSet.Locale = CultureInfo.InvariantCulture;
            LoadDataSet(command, dataSet, startRecord, maxRecords, "Table");
            if (dataSet.Tables.Count > 0)
            {
                return dataSet.Tables[0];
            }
            return null;
        }
        #endregion

        #region Database methods
        /// <summary>
        /// Executes the Command and builds an IDataReader. 
        /// </summary>
        /// <param name="command">Command.</param>
        /// <returns>An IDataReader object. </returns>
        public IDataReader ExecuteReader(CommonCommand command)
        {
            return this._database.ExecuteReaderCommand(command);
        }
        /// <summary>
        /// Executes a Command and returns the number of rows affected. 
        /// </summary>
        /// <param name="command">Command.</param>
        /// <returns>The number of rows affected. </returns>
        public int ExecuteNoQuery(CommonCommand command)
        {
            return this._database.ExecuteNonQueryCommand(command);
        }
        /// <summary>
        /// Executes the query, and returns the first column of the first row in the resultset returned by the query. Extra columns or rows are ignored. 
        /// </summary>
        /// <param name="command">Command.</param>
        /// <returns>The first column of the first row in the resultset. </returns>
        public object ExecuteScalar(CommonCommand command)
        {
            return this._database.ExecuteScalarCommand(command);
        }

        /// <summary>
        /// Executes the Command and builds an IDataReader. 
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>An IDataReader object. </returns>
        public IDataReader ExecuteReader<T>(CommonCommand command)
        {
            return this._provider.ExecuteDataTableReaderCommand<T>(command);
        }
        /// <summary>
        /// Executes a Command and returns the number of rows affected. 
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>The number of rows affected. </returns>
        public int ExecuteNoQuery<T>(CommonCommand command)
        {
            return this._provider.ExecuteDataTableNonQueryCommand<T>(command);
        }
        /// <summary>
        /// Executes the query, and returns the first column of the first row in the resultset returned by the query. Extra columns or rows are ignored. 
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>The first column of the first row in the resultset. </returns>
        public object ExecuteScalar<T>(CommonCommand command)
        {
            return this._provider.ExecuteDataTableScalarCommand<T>(command);
        }
        #endregion

        #region Query
        /// <summary>
        /// Query data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="columns">Columns.</param>
        /// <returns>Enumerator of given Type.</returns>
        public IEnumerable<T> Query<T>(params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetEnumerator();
            }
            else
            {
                return dataObjectAdapter.GetEnumerator(columns);
            }
        }
        /// <summary>
        /// Query data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Enumerator of given Type.</returns>
        public IEnumerable<T> Query<T>(ConditionExpression condition, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetEnumerator(condition);
            }
            else
            {
                return dataObjectAdapter.GetEnumerator(columns, condition);
            }
        }
        /// <summary>
        /// Query data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <param name="columns">Columns.</param>
        /// <returns>Enumerator of given Type.</returns>
        public IEnumerable<T> Query<T>(ConditionExpression condition, int startRecord, int maxRecords, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetEnumerator(condition, startRecord, maxRecords);
            }
            else
            {
                return dataObjectAdapter.GetEnumerator(columns, condition, startRecord, maxRecords);
            }
        }

        /// <summary>
        /// Query data for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="columns">Columns.</param>
        /// <returns>IList of given Type.</returns>
        public List<T> QueryForList<T>(params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetDataList();
            }
            else
            {
                return dataObjectAdapter.GetDataList(columns);
            }
        }
        /// <summary>
        /// Query data for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>IList of given Type.</returns>
        public List<T> QueryForList<T>(ConditionExpression condition, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetDataList(condition);
            }
            else
            {
                return dataObjectAdapter.GetDataList(columns, condition);
            }
        }
        /// <summary>
        /// Query data for List.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <param name="columns">Columns.</param>
        /// <returns>IList of given Type.</returns>
        public List<T> QueryForList<T>(ConditionExpression condition, int startRecord, int maxRecords, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetDataList(condition, startRecord, maxRecords);
            }
            else
            {
                return dataObjectAdapter.GetDataList(columns, condition, startRecord, maxRecords);
            }
        }

        /// <summary>
        /// Query data for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="columns">Columns.</param>
        /// <returns>DataTable.</returns>
        public System.Data.DataTable QueryForDataTable<T>(params ColumnExpression[] columns)
        {
            if ((columns == null) || (columns.Length == 0))
            {
                return this._provider.GetDataTable(typeof(T));
            }
            else
            {
                return this._provider.GetDataTable(typeof(T), columns);
            }
        }
        /// <summary>
        /// Query data for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>DataTable.</returns>
        public System.Data.DataTable QueryForDataTable<T>(ConditionExpression condition, params ColumnExpression[] columns)
        {
            if ((columns == null) || (columns.Length == 0))
            {
                return this._provider.GetDataTable(typeof(T), condition);
            }
            else
            {
                return this._provider.GetDataTable(typeof(T), columns, condition);
            }
        }
        /// <summary>
        /// Query data for DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <param name="columns">Columns.</param>
        /// <returns>DataTable.</returns>
        public System.Data.DataTable QueryForDataTable<T>(ConditionExpression condition, int startRecord, int maxRecords, params ColumnExpression[] columns)
        {
            if ((columns == null) || (columns.Length == 0))
            {
                return this._provider.GetDataTable(typeof(T), condition, startRecord, maxRecords);
            }
            else
            { 
                return this._provider.GetDataTable(typeof(T), columns, condition, startRecord, maxRecords);
            }
        }
        #endregion

        #region Datatable
        /// <summary>
        /// Update DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataTable">DataTable.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        public int UpdateDataTable<T>(System.Data.DataTable dataTable, params ColumnExpression[] columns)
        {
            if ((columns == null) || (columns.Length == 0))
            {
                return this._provider.Update(typeof(T), dataTable);
            }
            else
            {
                return this._provider.Update(typeof(T), dataTable, columns);
            }
        }
        /// <summary>
        /// Create an empty DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="columns">Columns.</param>
        /// <returns>DataTable.</returns>
        public System.Data.DataTable CreateDataTable<T>(params ColumnExpression[] columns)
        {
            if ((columns == null) || (columns.Length == 0))
            {
                return this._provider.GetDataTableAdapter(typeof(T)).CreateDataTable();
            }
            else
            {
                string[] columnNames = new string[columns.Length];
                for (int i = 0; i < columns.Length; i++)
                {
                    columnNames[i] = (string)columns[i];
                }
                return this._provider.GetDataTableAdapter(typeof(T)).CreateDataTable(columnNames);
            }
        }
  
        /// <summary>
        /// Fill DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataTable">DataTable.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully added to or refreshed. This does not include rows affected by statements that do not return rows. </returns>
        public int FillDataTable<T>(System.Data.DataTable dataTable, params ColumnExpression[] columns)
        {
            if ((columns == null) || (columns.Length == 0))
            {
                return this._provider.Fill<T>(dataTable);
            }
            else
            {
                return this._provider.Fill<T>(dataTable, columns);
            }
        }
        /// <summary>
        /// Fill DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataTable">DataTable.</param>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully added to or refreshed. This does not include rows affected by statements that do not return rows. </returns>
        public int FillDataTable<T>(System.Data.DataTable dataTable, ConditionExpression condition, params ColumnExpression[] columns)
        {
            if ((columns == null) || (columns.Length == 0))
            {
                return this._provider.Fill<T>(dataTable, condition);
            }
            else
            {
                return this._provider.Fill<T>(dataTable, columns, condition);
            }
        }
        /// <summary>
        /// Fill DataTable.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataTable">DataTable.</param>
        /// <param name="condition">Condition.</param>
        /// <param name="startRecord">The zero-based record number to start with. </param>
        /// <param name="maxRecords">The maximum number of records to retrieve. </param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully added to or refreshed. This does not include rows affected by statements that do not return rows. </returns>
        public int FillDataTable<T>(System.Data.DataTable dataTable, ConditionExpression condition, int startRecord, int maxRecords, params ColumnExpression[] columns)
        {
            if ((columns == null) || (columns.Length == 0))
            {
                return this._provider.Fill<T>(dataTable, condition, startRecord, maxRecords);
            }
            else
            {
                return this._provider.Fill<T>(dataTable, columns, condition, startRecord, maxRecords);
            }
        }
        #endregion

        #region  Single entity
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Data.</returns>
        public T GetData<T>(T dataObject, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetData(dataObject);
            }
            else
            {
                return dataObjectAdapter.GetData(dataObject, columns);
            }
        }
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKey">Primary key value.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Data.</returns>
        public T GetData<T>(object primaryKey, params ColumnExpression[] columns)
        {
            return GetDataByKey<T>(primaryKey, columns);
        }
        public T GetDataByKey<T>(object primaryKey, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetDataByPrimaryKey(primaryKey);
            }
            else
            {
                return dataObjectAdapter.GetDataByPrimaryKey(primaryKey, columns);
            }
        }
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKeys">An array of primary key values.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Data.</returns>
        public T GetData<T>(object[] primaryKeys, params ColumnExpression[] columns)
        {
            return GetDataByKey<T>(primaryKeys, columns);
        }
        public T GetDataByKey<T>(object[] primaryKeys, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetData(primaryKeys);
            }
            else
            {
                return dataObjectAdapter.GetData(primaryKeys, columns);
            }
        }
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>Data.</returns>
        public T GetData<T>(ConditionExpression condition, params ColumnExpression[] columns)
        {
            IList<T> list = QueryForList<T>(condition, 0, 1, columns);
            if ((list != null) && (list.Count > 0))
            {
                return list[0];
            }
            return default(T);
        }
 
        /// <summary>
        /// Get data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="command">Command.</param>
        /// <returns>Data.</returns>
        public T GetData<T>(CommonCommand command)
        {
            IList<T> list = ExecuteForList<T>(command, 0, 1);
            if ((list != null) && (list.Count > 0))
            {
                return list[0];
            }
            return default(T);
        }

        /// <summary>
        /// Insert data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully inserted. </returns>
        public int Insert<T>(T dataObject, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.Insert(dataObject);
            }
            else
            {
                 return dataObjectAdapter.Insert(dataObject, columns);
           }
        }

        /// <summary>
        /// Update data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        public int Update<T>(T dataObject, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.Update(dataObject);
            }
            else
            {
                return dataObjectAdapter.Update(dataObject, columns);
            }
        }
        /// <summary>
        /// Update data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKey">Primary key value.</param>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        public int Update<T>(object primaryKey, T dataObject, params ColumnExpression[] columns)
        {
            return UpdateByKey(primaryKey, dataObject, columns);
        }
        public int UpdateByKey<T>(object primaryKey, T dataObject, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.Update(new object[] { primaryKey }, dataObject);
            }
            else
            {
                return dataObjectAdapter.Update(new object[] { primaryKey }, dataObject, columns);
            }
        }
        /// <summary>
        /// Update data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKeys">An array of primary key values.</param>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        public int Update<T>(object[] primaryKeys, T dataObject, params ColumnExpression[] columns)
        {
            return UpdateByKey<T>(primaryKeys, dataObject, columns);
        }
        public int UpdateByKey<T>(object[] primaryKeys, T dataObject, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.Update(primaryKeys, dataObject);
            }
            else
            {
                return dataObjectAdapter.Update(primaryKeys, dataObject, columns);
            }
        }

        /// <summary>
        /// Save data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        public int Save<T>(T dataObject, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.Save(dataObject);
            }
            else
            {
                return dataObjectAdapter.Save(dataObject, columns);
            }
        }

        /// <summary>
        /// Delete data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <returns>The number of rows successfully deleted. </returns>
        public int Delete<T>(T dataObject)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            return dataObjectAdapter.Delete(dataObject);
        }
        /// <summary>
        /// Delete data.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKeys">Primary key values.</param>
        /// <returns>The number of rows successfully deleted. </returns>
        public int Delete<T>(params object[] primaryKeys)
        {
            return DeleteByKey<T>(primaryKeys);
        }
        public int DeleteByKey<T>(params object[] primaryKeys)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            return dataObjectAdapter.Delete(primaryKeys);
        }

        /// <summary>
        /// Check whether data exists or not.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <returns>If data exists return true, otherwise return false.</returns>
        public bool Exists<T>(T dataObject)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            return dataObjectAdapter.Exists(dataObject);
        }
        /// <summary>
        /// Check whether data exists or not.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="primaryKeys">Primary key values.</param>
        /// <returns>If data exists return true, otherwise return false.</returns>
        public bool Exists<T>(params object[] primaryKeys)
        {
            return ExistsByKey<T>(primaryKeys);
        }
        public bool ExistsByKey<T>(params object[] primaryKeys)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            return dataObjectAdapter.Exists(primaryKeys);
        }
        #endregion

        #region Batch operation
        /// <summary>
        /// Delete data according condition.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <returns>The number of rows successfully deleted. </returns>
        public int Delete<T>(ConditionExpression condition)
        {
            DataTableAdapter dataTableAdapter = this._provider.GetDataTableAdapter(typeof(T));
            return dataTableAdapter.Delete(condition);
        }
        
        /// <summary>
        /// Check whether data exists or not, according condtion.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="condition">Condition.</param>
        /// <returns>If data exists return true, otherwise return false.</returns>
        public bool Exists<T>(ConditionExpression condition)
        {
            return (this.GetCount<T>(condition) > 0) ? true : false;
        }

        /// <summary>
        /// Update data according condition.
        /// </summary>
        /// <typeparam name="T">Type.</typeparam>
        /// <param name="dataObject">Data object.</param>
        /// <param name="condition">Condition.</param>
        /// <param name="columns">Columns.</param>
        /// <returns>The number of rows successfully updated. </returns>
        public int Update<T>(T dataObject, ConditionExpression condition, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.UpdateByCondition(dataObject, condition);
            }
            else
            {
                return dataObjectAdapter.UpdateByCondition(dataObject, columns, condition);
            }
        }
        #endregion

        #region Bulk operation
        public int Delete<T>(IList<T> dataObjectList)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            return dataObjectAdapter.Delete(dataObjectList);
        }

        public int Exists<T>(IList<T> dataObjectList)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            return dataObjectAdapter.Exists(dataObjectList);
        }

        public int Update<T>(IList<T> dataObjectList, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.Update(dataObjectList);
            }
            else
            {
                return dataObjectAdapter.Update(dataObjectList, columns);
            }
        }

        public int Insert<T>(IList<T> dataObjectList, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.Insert(dataObjectList);
            }
            else
            {
                return dataObjectAdapter.Insert(dataObjectList, columns);
            }
        }

        public int Save<T>(IList<T> dataObjectList, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.Save(dataObjectList);
            }
            else
            {
                return dataObjectAdapter.Save(dataObjectList, columns);
            }
        }
        #endregion

        #region SharePoint
        public IDataReader QueryReader<T>(params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetDataReader();
            }
            else
            {
                return dataObjectAdapter.GetDataReader(columns);
            }
        }

        public IDataReader QueryReader<T>(ConditionExpression condition, params ColumnExpression[] columns)
        {
            DataObjectAdapter<T> dataObjectAdapter = this._provider.GetDataObjectAdapter<T>();
            if ((columns == null) || (columns.Length == 0))
            {
                return dataObjectAdapter.GetDataReader(condition);
            }
            else
            {
                return dataObjectAdapter.GetDataReader(columns, condition);
            }
        }
        #endregion
    }
}
